﻿@using Gurux.DLMS.AMI.Shared.DIs

@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Gurux.DLMS.AMI.Shared.DTOs
@using Gurux.DLMS.AMI.Shared.Rest
@using Gurux.DLMS.AMI.Shared.Enums
@using System.IO
@using Gurux.DLMS.AMI.Module
@using System.Linq
@using System.Net.Http.Headers
@using System.Text.Json
@using Microsoft.Extensions.Logging
@using Microsoft.Extensions.Options

@inject NavigationManager NavigationManager
@inject HttpClient Http
@inject IGXNotifier2 Notifier
@inject ILogger<Module> Logger
@inject GXModuleService modules
@implements IDisposable
@if (Active != null)
{
    <EditForm Model="@Active">
        <DataAnnotationsValidator />
        <ValidationSummary />
        @if (isAdding)
        {
            <tr>
                <th>
                    Upload File:
                </th>
                <th>
                    <p><InputFile OnChange="@LoadFile" /></p>
                </th>
            </tr>
        }
        else
        {
            <div class="row">
                <div style="width:100%">
                    <div class="form-group">
                        <InputNullableSwitch Text="@Properties.Resources.Active"
                        @bind-Value="Active.Active" />
                        <br />
                    </div>
                    <div class="form-group">
                        <label>@Properties.Resources.Name:</label>
                        <InputText id="name" class="form-control" readonly="readonly" @bind-Value="Active.Name" />
                    </div>
                    @if (_configurationUI != null)
                    {
                        RenderFragment renderFragment = (builder) =>
                        {
                            builder.OpenComponent(0, _configurationUI);
                            @if (_moduleSettings != null)
                            {
                                builder.AddAttribute(1, "Settings", _moduleSettings);
                            }
                            builder.AddComponentReferenceCapture(0, inst => { _module = (IAmiModuleSettings)inst; });
                            builder.CloseComponent();
                        };
                        <div>
                            @renderFragment
                        </div>
                    }
                    <div class="form-group">
                        <label>@Properties.Resources.Version:</label>
                        <InputText id="version" class="form-control" readonly="readonly" @bind-Value="Active.Version" />
                    </div>
                    <div class="form-group">
                        <label>@Properties.Resources.Installed:</label>
                        <InputDate Type="@InputDateType.DateTimeLocal" id="generation" class="form-control"
                                   readonly="readonly" @bind-Value="Active.CreationTime" />
                    </div>
                    @if (Active.Updated != null)
                    {
                        <div class="form-group">
                            <label>@Properties.Resources.Updated:</label>
                            <InputDate Type="@InputDateType.DateTimeLocal" id="generation" class="form-control"
                                       readonly="readonly" @bind-Value="Active.Updated" />
                        </div>
                    }
                </div>
            </div>
        }
    </EditForm>

    <Confirm @ref="RestartConfirmation"
             ConfirmationChanged="OnRestartConfirmation"
             ConfirmationTitle="Confirm restart"
             AllowDelete="false"
             OkTitle="@Properties.Resources.Restart"
             ConfirmationMessage="Server needs restart to apply the module changes. Do you want to restart the server now?">
    </Confirm>
}

@code {
    [CascadingParameter]
    private ModuleTab? Parent { get; set; }

    private GXModule? _active;

    private GXModule? Active
    {
        get
        {
            if (_active != null)
            {
                return _active;
            }
            return Parent?.Active;
        }
    }

    /// <summary>
    /// User action.
    /// </summary>
    [Parameter]
    public string? Action { get; set; }

    private CrudAction action;
    /// <summary>
    /// Selected item.
    /// </summary>
    [Parameter]
    public string? Id { get; set; }

    private Type? _configurationUI;
    /// <summary>
    /// User is verified before server is restart.
    /// </summary>
    protected ConfirmBase? RestartConfirmation;

    private IAmiModuleSettings? _module = null;
    private string? fileName = null;
    private bool isAdding = false;
    private bool isLoading;
    object? _moduleSettings;
    bool initialized;

    MultipartFormDataContent? content = null;

    private Task LoadFile(InputFileChangeEventArgs e)
    {
        fileName = e.File.Name;
        try
        {
            Notifier?.ClearStatus();
            foreach (var file in e.GetMultipleFiles())
            {
                try
                {
                    content = new MultipartFormDataContent();
                    //Max file size is 10 MB.
                    var fileContent = new StreamContent(file.OpenReadStream(10485760));
                    fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType);
                    content.Add(
                        content: fileContent,
                        name: "\"files\"",
                        fileName: file.Name);
                }
                catch (Exception ex)
                {
                    Logger.LogInformation("{FileName} not uploaded (Err: 6): {Message}", file.Name, ex.Message);
                    fileName = null;
                    Notifier?.ProcessError(ex);
                }
            }
        }
        catch (Exception ex)
        {
            fileName = null;
            Notifier?.ProcessError(ex);
        }
        return Task.CompletedTask;
    }

    /// <summary>
    /// Show module settings.
    /// </summary>
    /// <returns></returns>
    private async Task ShowModuleSettings()
    {
        _moduleSettings = null;
        if (Active != null && !string.IsNullOrEmpty(Active.ConfigurationUI))
        {
            _configurationUI = Type.GetType(Active.ConfigurationUI);
            if (_configurationUI == null)
            {
                //Load module UI if not loaded yet.
                var list = await modules.GetModule(Http, Active);
                foreach (var it in list)
                {
                    _configurationUI = it.GetType(Active.ConfigurationUI);
                    if (_configurationUI != null)
                    {
                        break;
                    }
                }
                if (_configurationUI == null)
                {
                    throw new Exception("Invalid ConfigurationUI " + Active.ConfigurationUI + ".");
                }
            }
            if (_module != null && !string.IsNullOrEmpty(Active.Settings))
            {
                var settings = _module.GetType().GetProperty("Settings");
                if (settings != null && settings.CanRead && settings.CanWrite &&
                        settings.GetCustomAttributes(typeof(ParameterAttribute), false).Any())
                {
                    _moduleSettings = JsonSerializer.Deserialize(Active.Settings, settings.PropertyType);
                }
            }
        }
    }

    protected override async Task OnInitializedAsync()
    {
        try
        {
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            Notifier.Clear();
            action = ClientHelpers.GetAction(Action);
            if (action != CrudAction.Create || ((Active == null || Active.Id == null) && Id != null))
            {
                //Get module data.
                var tmp = (await Http.GetAsJsonAsync<GetModuleResponse>(string.Format("api/Module?id={0}", Id)));
                if (tmp?.Item != null)
                {
                    _active = tmp.Item;
                    await ShowModuleSettings();
                }
                else
                {
                    NavigationManager.NavigateTo("404");
                }
            }
            if (Active == null)
            {
                throw new ArgumentException(Properties.Resources.InvalidTarget);
            }
            action = ClientHelpers.GetAction(Action);
            isAdding = action == CrudAction.Create;
            if (action == CrudAction.Delete)
            {
                Notifier.AddMenuItem(new GXMenuItem() { Text = Properties.Resources.Remove, Icon = "oi oi-trash", OnClick = OnSave });
            }
            else
            {
                Notifier.AddMenuItem(new GXMenuItem() { Text = Properties.Resources.Save, Icon = "oi oi-pencil", OnClick = OnSave });
            }
            Notifier.AddMenuItem(new GXMenuItem() { Text = Properties.Resources.Cancel, Icon = "oi oi-action-undo", OnClick = OnCancel });
            Notifier.UpdateButtons();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }

    /// <summary>
    /// Save module.
    /// </summary>
    public async void OnSave()
    {
        HttpResponseMessage response;
        try
        {
            if (Active == null)
            {
                throw new Exception(Properties.Resources.InvalidTarget);
            }
            Notifier.ProgressStart();
            Notifier.ClearStatus();
            if (action == CrudAction.Create)
            {
                if (content == null)
                {
                    throw new Exception("Module file is not selected.");
                }
                response = await Http.PostAsync("api/Module/Add", content);
                ClientHelpers.ValidateStatusCode(response);
                AddModuleResponse? ret = await response.Content.ReadFromJsonAsync<AddModuleResponse>();
                if (ret != null && ret.Modules != null && ret.Modules.Any())
                {
                    _active = ret.Modules[0];
                    if (Active != null)
                    {
                        isAdding = false;
                        Notifier.UpdateData(GXPages.Modules, Active);
                        Active.Modified = true;
                        await modules.LoadModules(Http);
                        await ShowModuleSettings();
                        Notifier.Action = CrudAction.Update;
                        StateHasChanged();
                        //                        ClientHelpers.NavigateTo(NavigationManager, Notifier, GXPages.ModuleManage);
                    }
                    if (ret.Restart)
                    {
                        RestartConfirmation?.Show();
                    }
                }
            }
            else if (action == CrudAction.Delete)
            {
                var ret = await Http.PostAsJson<RemoveModuleResponse>("api/Module/Delete", new RemoveModule() { Modules = new string[] { Active.Id } });
                if (ret.Restart)
                {
                    RestartConfirmation?.Show();
                }
            }
            else if (action == CrudAction.Update)
            {
                if (_module != null)
                {
                    var settings = _module.GetType().GetProperty("Settings");
                    if (settings != null && settings.CanRead && settings.CanWrite && settings.GetCustomAttributes(typeof(ParameterAttribute), false).Any())
                    {
                        _moduleSettings = settings.GetValue(_module);
                        if (_moduleSettings != null)
                        {
                            Active.Settings = JsonSerializer.Serialize(_moduleSettings);
                        }
                        Notifier.ShowInformation("Settings saved.", true);
                    }
                }
                UpdateModule req = new UpdateModule() { Module = Active };
                await Http.PostAsJson<UpdateModuleResponse>("api/Module/Update", req);
            }
            else
            {
                throw new Exception(Properties.Resources.InvalidTarget);
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
        finally
        {
            Notifier?.ProgressEnd();
        }
    }

    /// <summary>
    /// Cancel.
    /// </summary>
    private void OnCancel()
    {
        if (_module != null)
        {
            _module.Cancel();
        }
        ClientHelpers.NavigateToLastPage(NavigationManager, Notifier);
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (!initialized && _module != null)
        {
            //Set module settings.
            initialized = true;
            _module.Initialize();
        }
        else if (_module != null && initialized)
        {
            //Get module settings if UI is updated.
            _moduleSettings = null;
            var settings = _module.GetType().GetProperty("Settings");
            if (settings != null)
            {
                _moduleSettings = settings.GetValue(_module);
            }
        }
        base.OnAfterRender(firstRender);
    }

    public void Dispose()
    {
        if (_module != null)
        {
            /*

                    //Save module settings if page is changed.
                    _moduleSettings = null;
                    foreach (var i in _module.GetType().GetInterfaces())
                    {
                        if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IGXModuleUINotifications2<>))
                        {
                            _moduleSettings = i.GetProperty("Settings").GetValue(_module);
                            break;
                        }
                    }
                    if (_moduleSettings != null)
                    {
                        Active.Settings = JsonSerializer.Serialize(_moduleSettings);
                    }
                */
        }
    }

    /// <summary>
    /// Clear the workflow log list.
    /// </summary>
    public async Task OnRestartConfirmation(ConfirmArgs args)
    {
        try
        {
            if (args.Confirm)
            {
                StopApplicationRequest req = new StopApplicationRequest();
                await Http.PostAsJson("api/Configuration/Restart", req);
            }
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
        catch (Exception ex)
        {
            Notifier?.ProcessError(ex);
        }
    }
}
